#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
#include <regex.h>
#include <sys/ipc.h>
#include <sys/msg.h>

#include "../LED/led.h"
#include "../Carama/carama.h"
#include "socket_thread.h"
#include "../FIFO/fifo.h"
#include "../Carama/carama.h"

extern struct kfifo *global_carama_fifo;             // 存放carama的每帧的数据
static int send_fd;                                 // 接收发送的信息
static int control_fd;                              // 专门用来接受控制信息的



int client_init(const char* server_addr, unsigned short int host,unsigned char type) {
    int socketfd = -1; 
    struct sockaddr_in serveraddr; 

    // 创建套接字
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd == -1) {
        perror("Socket creation failed");
        return -1;
    }

    // 设置服务器地址
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(host);

    if (inet_pton(AF_INET, server_addr, &serveraddr.sin_addr) <= 0) {
        printf("inet_pton error for %s \n", server_addr);
        close(socketfd);
        return -1;
    }

    // 阻塞模式下连接服务器
    if (connect(socketfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
        perror("Connect error");
        close(socketfd);
        return -1;
    }

    printf("Connection established\n");
    printf("=========client init ready, send msg to server.....=====\n");
    if(type == 0)
        send_fd = socketfd;
    else
        control_fd = socketfd;
    return socketfd;
}


void* client_send_thread(void * arg)
{
    static unsigned int readIndex = 0;
    void * recv_buffer = malloc(CARAMA_MAX_WIDTH * CARAMA_MAX_HEIGHT * 2);
    if(recv_buffer == NULL)
        pthread_exit(NULL);
    memset(recv_buffer,0,(CARAMA_MAX_WIDTH * CARAMA_MAX_HEIGHT * 2));
    struct carama_msg recv_msg = {0};    // 用来接受信息

    unsigned char send_buf[12];         //第一次发送的时候需要发送的东西
    unsigned char recv_buf[12];         
    ssize_t send_bytes = 0;              // 发送的字节数
    ssize_t recv_bytes = 0;
    while(1) {
        // 非阻塞的方式接受某个消息
        // 接收到了 那就修正
        kfifo_read(global_carama_fifo,recv_buffer,CARAMA_MAX_WIDTH * CARAMA_MAX_HEIGHT * 2,
                    &recv_msg,&readIndex);
        //printf("send线程读取到了一帧%d\r\n",readIndex);
        // 先发送得到的大小
        send_buf[0] = 0xff;
        send_buf[1] = 0xff;
        send_buf[2] = (recv_msg.real_size >>24) &0xFF;
        send_buf[3] = (recv_msg.real_size>>16) &0xFF;
        send_buf[4] = (recv_msg.real_size>>8) &0xFF;
        send_buf[5] = (recv_msg.real_size) &0xFF;
        // 显示的 宽度
        send_buf[6] = (recv_msg.width>>8) &0xFF;
        send_buf[7] = (recv_msg.width) &0xFF;
        //显示的 高度
        send_buf[8] = (recv_msg.height>>8) &0xFF;
        send_buf[9] = (recv_msg.height) &0xFF;
        send_buf[10] = 0xfe;
        send_buf[11] = 0xfe;
        send_bytes = send(send_fd, send_buf, 12, 0);
        if (send_bytes < 0) {
            goto send_free_err;
        }
        recv_bytes = recv(send_fd, recv_buf, 12, 0);
        if(recv_bytes > 0 && recv_buf[0] == 'O' && recv_buf[1] == 'K') //收到ok才接着干
        {
            //printf("send线程发送数据头完毕%d\r\n",readIndex);
            send_bytes = send(send_fd, recv_buffer, recv_msg.real_size, 0);
            if(send_bytes < 0)
                goto send_free_err;
            recv_bytes = recv(send_fd, recv_buf, 12, 0); //收到什么都无所谓重要的是收到
            //printf("send线程接收到了收到的信息,发送的字节数为%d\r\n",send_bytes);
            if(recv_bytes < 0)
                goto send_free_err;
        } else if(recv_bytes < 0) {
            goto send_free_err;
        }
    }
send_free_err:
    close(send_fd);
    free(recv_buffer);
    pthread_exit(NULL);
}

void* client_control_thread(void * arg)
{
    // 解析信息 并返回
    int msg_fd = *(int *) arg;
    static char *pattern = "^[0-9]{1,3}(\\.[0-9]{1,3}){3}:[0-9]+:([A-Z]+):([a-zA-Z]+):([0-9]+)$";
    char recv_data[50];
    char send_message[30];
    regex_t regex;
    regmatch_t matches[5];
    if (regcomp(&regex, pattern, REG_EXTENDED) != 0) {
        fprintf(stderr, "Could not compile regex\r\n");
        pthread_exit(NULL);
    }
    // 提取匹配到的内容
    char requestType[5];
    char subString[15];
    char number[15];
    struct msg message = {0};
    while(1) {
        memset(recv_data,0,50);
        // 这里的话后面可以给个flag然后看是recv哪一个
        ssize_t recv_bytes = recv(control_fd, recv_data, 50, 0);
        printf("控制线程接收到数据了%d\r\n",recv_bytes);
        int reti = regexec(&regex, recv_data, 5, matches, 0);
        if (!reti) {
            snprintf(requestType, matches[2].rm_eo - matches[2].rm_so + 1, "%.*s", (int)(matches[2].rm_eo - matches[2].rm_so), recv_data + matches[2].rm_so);
            requestType[matches[2].rm_eo - matches[2].rm_so] = '\0';
            snprintf(subString, matches[3].rm_eo - matches[3].rm_so + 1, "%.*s", (int)(matches[3].rm_eo - matches[3].rm_so), recv_data + matches[3].rm_so);
            subString[matches[3].rm_eo - matches[3].rm_so] = '\0'; 
            snprintf(number, matches[4].rm_eo - matches[4].rm_so + 1, "%.*s", (int)(matches[4].rm_eo - matches[4].rm_so), recv_data + matches[4].rm_so);
            number[matches[4].rm_eo - matches[4].rm_so] = '\0'; 
            if(strcmp(requestType,"SET") == 0)
            {
                // 设置Carama格式
                if(strcmp(subString,"Carama") == 0 &&strlen(number) == 11)
                {
                    char get_width[5];  
                    strncpy(get_width, number, 4);  //得到的高度
                    get_width[4] = '\0';  
                    int width = atoi(get_width);

                    char get_height[5];
                    strncpy(get_height, number+4, 4);  //得到的高度
                    get_height[4] = '\0'; 
                    int height = atoi(get_height);

                    char get_fps[4];
                    strncpy(get_fps, number+8, 3);  //得到的高度
                    get_fps[3] = '\0'; 
                    int fps = atoi(get_fps);

                    message.type = CARAMA_MSG_TYPE;
                    message.detail_msg.carama_msg = CARAMA_FROMAT_CHANGE;
                    message.detail_msg.msg_buffer[0] = width & 0xff;
                    message.detail_msg.msg_buffer[1] = (width >> 8) & 0xff;

                    message.detail_msg.msg_buffer[2] = height & 0xff;
                    message.detail_msg.msg_buffer[3] = (height >> 8) & 0xff;

                    message.detail_msg.msg_buffer[4] = fps & 0xff;
                    message.detail_msg.msg_buffer[5] = (fps >> 8) & 0xff;
                    message.detail_msg.msg_length = 6;
                    msgsnd(msg_fd, &message, sizeof(message.detail_msg), IPC_NOWAIT);
                }
                else if(strcmp(subString,"LED") == 0 &&strlen(number) == 5)
                {
                    char led_id[3];  
                    strncpy(led_id, number, 2);  //得到的高度
                    led_id[2] = '\0';  

                    char led_brightness[4];
                    strncpy(led_brightness, number+2, 3);  //得到的高度
                    led_brightness[3] = '\0'; 
                    write_led_lightness(atoi(led_id),atoi(led_brightness));
                }
                else
                    printf("你在SET啥\r\n");
                // 设置LED亮度
            }
            else if(strcmp(requestType,"GET") == 0)
            {
                //得到Carama格式
                if (strcmp(subString,"Carama") == 0)
                {
          
                    get_current_format(send_message, 30);
                    send(control_fd, send_message, strlen(send_message), 0); //发送过去
                }
                else if(strcmp(subString,"LED") == 0 &&strlen(number) == 2)
                {
                    
                    int lightness = get_led_lightness(atoi(number));
                    if(lightness != -1)
                    {
                        snprintf(send_message, sizeof(send_message), "LED%s:%d", number, lightness); 
                        send(control_fd, send_message, strlen(send_message), 0); //发送过去
                    }
                } else
                    printf("GET 格式错误\r\n");
                //得到LED亮度
            }
            else
                printf("error request type\r\n");
        } else {
            recv_data[recv_bytes] = '\0';
            printf("接收到的数据%s,格式解析失败\r\n",recv_data);
        }
    }
}